﻿//-----------------------------------------------------------------------
// <copyright file="AccountRepositoryTest.cs" company="FastNET Services">
//     Copyright (c) 2008-2009. All Rights Reserved.
// </copyright>
// <license>
//     GPLv2
// </license>
// <warranty>
//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
//     BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
//     DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </warranty>
//-----------------------------------------------------------------------
#region Usings

using System;
using System.Collections.Generic;
using System.Data.EntityClient;
using System.Linq;
using GateShift.Common.Repository;
using GateShift.Common.Repository.Interfaces.DataInterfaces;
using GateShift.Services.GameData.Entities;
using GateShift.Services.GameData.Repositories;
using GateShift.Testing.Mockup.DataLayer;
using GateShift.Testing.Services.GameData.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting;

#endregion

namespace GateShift.Testing.Services.GameData.Repositories
{
    /// <summary>
    /// This is a test class for AccountRepository and is intended
    /// to contain all AccountRepository Unit Tests
    /// </summary>
    [TestClass]
    public class AccountRepositoryTest
    {
        #region Fields

        private static EntityConnection _connection;
        private AccountRepository _repository;

        #endregion

        #region TestContext

        /// <summary>
        /// Gets or sets the test context which provides
        /// information about and functionality for the current test run.
        /// </summary>
        public TestContext TestContext { get; set; }

        #endregion

        #region Additional test attributes

        /// <summary>
        /// Run initialization for all unit tests for this class
        /// </summary>
        /// <param name="testContext">TestContext for this class during initialization</param>
        [ClassInitialize]
        public static void ClassInitialize(TestContext testContext)
        {
            _connection = DBHelper.CreateConnection();
            _connection.Open();
            DBHelper.ClearDatabase();
        }

        /// <summary>
        /// Run cleanup for all unit tests for this class
        /// </summary>
        [ClassCleanup]
        public static void ClassCleanup()
        {
            _connection.Close();
        }

        /// <summary>
        /// Run individual unit test preparation
        /// </summary>
        [TestInitialize]
        public void TestInitialize()
        {
            _repository = new AccountRepository(_connection);
        }

        /// <summary>
        /// Run individual unit test cleanup
        /// </summary>
        [TestCleanup]
        public void TestCleanup()
        {
            DBHelper.ClearDatabase();
        }

        #endregion

        #region Connection

        /// <summary>
        /// A test for Connection
        /// </summary>
        [TestMethod]
        public void Connection()
        {
            AccountRepository_Accessor target = new AccountRepository_Accessor(_connection);
            Assert.AreEqual(_connection, target.Connection);
        }

        #endregion

        #region Save

        /// <summary>
        /// A test for Save
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void Save_Null_ThrowsException()
        {
            _repository.Save(null);
        }

        /// <summary>
        /// A test for Save
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidCastException))]
        public void Save_InvalidData_ThrowsException()
        {
            _repository.Save(new MockAccount());
        }

        /// <summary>
        /// A test for Save
        /// </summary>
        [TestMethod]
        public void Save_Success()
        {
            _repository.Save(AccountHelper.CreateAccount());

            using (EntityDataAdapter dataSource = new EntityDataAdapter(_connection))
            {
                Assert.AreEqual(1, dataSource.Accounts.Count());
            }
        }

        #endregion

        #region RetrieveByUserName

        /// <summary>
        /// A test for RetrieveByUserName
        /// </summary>
        [TestMethod]
        public void RetrieveByUserName_Success()
        {
            Account createdAccount = AccountHelper.CreateDBAccount();

            IAccountData retrievedAccount = _repository.RetrieveByUserName(createdAccount.AccountName);

            Assert.AreEqual(createdAccount.ID, retrievedAccount.ID, "ID");
            Assert.AreEqual(createdAccount.AccountName, retrievedAccount.AccountName, "AccountName");
        }

        /// <summary>
        /// A test for RetrieveByUserName
        /// </summary>
        [TestMethod]
        public void RetrieveByUserName_NotFound()
        {
            IAccountData retrievedAccount = _repository.RetrieveByUserName(Guid.NewGuid().ToString());

            Assert.IsNull(retrievedAccount, "Account Found");
        }

        /// <summary>
        /// A test for RetrieveByUserName
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void RetrieveByUserName_NullAccountName()
        {
            _repository.RetrieveByUserName(null);
        }

        #endregion

        #region RetrieveByEmailAddress

        /// <summary>
        /// A test for RetrieveByEmailAddress
        /// </summary>
        [TestMethod]
        public void RetrieveByEmailAddress_Success()
        {
            Account createdAccount = AccountHelper.CreateDBAccount();

            IAccountData retrievedAccount = _repository.RetrieveByEmailAddress(createdAccount.EmailAddress);

            Assert.AreEqual(createdAccount.ID, retrievedAccount.ID, "ID");
            Assert.AreEqual(createdAccount.EmailAddress, retrievedAccount.EmailAddress, "EmailAddress");
        }

        /// <summary>
        /// A test for RetrieveByEmailAddress
        /// </summary>
        [TestMethod]
        public void RetrieveByEmailAddress_NotFound()
        {
            IAccountData retrievedAccount = _repository.RetrieveByEmailAddress(Guid.NewGuid().ToString());

            Assert.IsNull(retrievedAccount, "Account Found");
        }

        /// <summary>
        /// A test for RetrieveByEmailAddress
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void RetrieveByEmailAddress_NullEmailAddress()
        {
            _repository.RetrieveByEmailAddress(null);
        }

        #endregion

        #region Retrieve

        #region NoParams

        /// <summary>
        /// A test for Retrieve
        /// </summary>
        [TestMethod]
        public void Retrieve_NoParams_3Items()
        {
            List<Account> createdAccounts = new List<Account>
                                                {
                                                    AccountHelper.CreateDBAccount(),
                                                    AccountHelper.CreateDBAccount(),
                                                    AccountHelper.CreateDBAccount()
                                                };

            IEnumerable<IAccountData> retrievedAccounts = _repository.Retrieve();

            Assert.IsNotNull(retrievedAccounts);
            Assert.AreEqual(createdAccounts.Count, retrievedAccounts.Count(), "Count Mismatch");

            foreach (IAccountData account in retrievedAccounts)
            {
                bool foundItem = false;

                foreach (Account createdItem in createdAccounts)
                {
                    if (createdItem.ID != account.ID)
                    {
                        continue;
                    }

                    foundItem = true;
                    break;
                }

                if (!foundItem)
                {
                    Assert.Fail("Account not found in expected list");
                }
            }
        }

        /// <summary>
        /// A test for Retrieve
        /// </summary>
        [TestMethod]
        public void Retrieve_NoParams_0Items()
        {
            List<Account> createdAccounts = new List<Account>();

            IEnumerable<IAccountData> retrievedAccounts = _repository.Retrieve();

            Assert.IsNotNull(retrievedAccounts);
            Assert.AreEqual(createdAccounts.Count, retrievedAccounts.Count(), "Count Mismatch");
        }

        #endregion

        #region ByID

        /// <summary>
        /// A test for Retrieve
        /// </summary>
        [TestMethod]
        public void Retrieve_ByID_Success()
        {
            Account createdAccount = AccountHelper.CreateDBAccount();

            IAccountData retrievedAccount = _repository.Retrieve(createdAccount.ID);

            Assert.AreEqual(createdAccount.ID, retrievedAccount.ID, "ID");
            Assert.AreEqual(createdAccount.EmailAddress, retrievedAccount.EmailAddress, "EmailAddress");
        }

        /// <summary>
        /// A test for Retrieve
        /// </summary>
        [TestMethod]
        public void Retrieve_ByID_NoneFound()
        {
            IAccountData retrievedAccount = _repository.Retrieve(new Identity(Guid.Empty));

            Assert.IsNull(retrievedAccount, "Account Found");
        }

        /// <summary>
        /// A test for Retrieve
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidCastException))]
        public void Retrieve_ByID_InvalidIdentity()
        {
            // Accounts use Guids not ints
            _repository.Retrieve(new Identity(123));
        }

        #endregion

        #endregion

        #region EmailAddressExists

        /// <summary>
        /// A test for EmailAddressExists
        /// </summary>
        [TestMethod]
        public void EmailAddressExists_Success()
        {
            Account createdAccount = AccountHelper.CreateDBAccount();

            Assert.IsTrue(_repository.EmailAddressExists(createdAccount.EmailAddress, null), "Account Not Found");
        }

        /// <summary>
        /// A test for EmailAddressExists
        /// </summary>
        [TestMethod]
        public void EmailAddressExists_Failure_IgnoreID()
        {
            Account createdAccount = AccountHelper.CreateDBAccount();

            Assert.IsFalse(_repository.EmailAddressExists(createdAccount.EmailAddress, createdAccount.ID), "Account Found");
        }

        /// <summary>
        /// A test for EmailAddressExists
        /// </summary>
        [TestMethod]
        public void EmailAddressExists_Failure_DoNotIgnoreID()
        {
            Assert.IsFalse(_repository.EmailAddressExists(Guid.NewGuid().ToString(), null), "Account Found");
        }

        /// <summary>
        /// A test for EmailAddressExists
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void EmailAddressExists_NullEmailAddress()
        {
            _repository.EmailAddressExists(null, null);
        }

        /// <summary>
        /// A test for EmailAddressExists
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidCastException))]
        public void EmailAddressExists_InvalidIDType()
        {
            _repository.EmailAddressExists(Guid.NewGuid().ToString(), new Identity(123));
        }

        #endregion

        #region AccountNameExists

        /// <summary>
        /// A test for AccountNameExists
        /// </summary>
        [TestMethod]
        public void AccountNameExists_Success()
        {
            Account createdAccount = AccountHelper.CreateDBAccount();

            Assert.IsTrue(_repository.AccountNameExists(createdAccount.AccountName, null), "Account Not Found");
        }

        /// <summary>
        /// A test for AccountNameExists
        /// </summary>
        [TestMethod]
        public void AccountNameExists_Failure_IgnoreID()
        {
            Account createdAccount = AccountHelper.CreateDBAccount();

            Assert.IsFalse(_repository.AccountNameExists(createdAccount.AccountName, createdAccount.ID), "Account Found");
        }

        /// <summary>
        /// A test for AccountNameExists
        /// </summary>
        [TestMethod]
        public void AccountNameExists_Failure_DoNotIgnoreID()
        {
            Assert.IsFalse(_repository.AccountNameExists(Guid.NewGuid().ToString(), null), "Account Found");
        }

        /// <summary>
        /// A test for AccountNameExists
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AccountNameExists_Failure_NullAccountName()
        {
            _repository.AccountNameExists(null, null);
        }

        /// <summary>
        /// A test for AccountNameExists
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidCastException))]
        public void AccountNameExists_InvalidIDType()
        {
            _repository.AccountNameExists(Guid.NewGuid().ToString(), new Identity(123));
        }

        #endregion

        #region Delete

        /// <summary>
        /// A test for Delete
        /// </summary>
        [TestMethod]
        public void Delete_Success()
        {
            Account createdAccount = AccountHelper.CreateDBAccount();

            _repository.Delete(createdAccount);

            using (EntityDataAdapter dataSource = new EntityDataAdapter(_connection))
            {
                Assert.AreEqual(0, dataSource.Accounts.Count(), "Accounts Found");
            }
        }

        /// <summary>
        /// A test for Delete
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void Delete_NullIAccount()
        {
            _repository.Delete(null);
        }

        /// <summary>
        /// A test for Delete
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidCastException))]
        public void Delete_InvalidIAccount()
        {
            _repository.Delete(new MockAccount());
        }

        /// <summary>
        /// A test for Delete
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void Delete_AlreadyDeleted()
        {
            Account createdAccount = AccountHelper.CreateDBAccount();

            _repository.Delete(createdAccount);

            // Try to redelete it
            _repository.Delete(createdAccount);
        }

        /// <summary>
        /// A test for Delete
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void Delete_DeleteNewAccount()
        {
            Account createdAccount = AccountHelper.CreateAccount();

            _repository.Delete(createdAccount);
        }

        #endregion

        #region Create

        /// <summary>
        /// A test for Create
        /// </summary>
        [TestMethod]
        public void Create()
        {
            IAccountData account = _repository.Create();

            Assert.IsNotNull(account, "Account is null");
        }

        #endregion
    }
}